
/*
2024-06-04.
Provide easyx image lib, operates.
public:
int exim::init();
HWND exim::init_display(int width, int height, int showconsole = 0);

24-06-11 18.18 finish
24-07-27 fix color.eq
*/
#include "easyx.h"
#include <exception>
#include <stdint.h>
#include <iso646.h>
#define pass
#define is ==
#define elif else if
#define GETEXIMAPI FORCEINLINE
typedef uint8_t color_t;
namespace exim
{
    // globals
    struct {
        HWND win;
        bool inited;
        int width;
        int height;
        int showConsole;
    } DisplayInfo;
    
    class Exception {
        public:
            TCHAR desc[360];
            LPCTSTR Desc;
            exim::Exception(LPCTSTR s) {
                this->Desc = s;
            }
            //240803
            exim::Exception(LPCTSTR s, int i) {
                _stprintf_s(this->desc, 360, L"%s %d.", s, i);
                this->Desc = this->desc;
            }
            LPCTSTR what() {
                https://blog.csdn.net/albertsh/article/details/100540338
                return this->Desc;
            }
    };
    
    HWND init_display(int width, int height, int showconsole = 0) {
        exim::DisplayInfo.width = width;
        exim::DisplayInfo.height = height;
        exim::DisplayInfo.showConsole = showconsole;
        exim::DisplayInfo.inited = true;
        return initgraph(width, height, showconsole);
    }
    
    bool init_text(LPCTSTR fontname, int height = 18) {
        LOGFONT f;
        gettextstyle(&f);
        f.lfHeight = height;
        if (fontname != nullptr){
            _tcscpy(f.lfFaceName, /*_T("黑体")*/ fontname);
        }
        f.lfQuality = ANTIALIASED_QUALITY;
        settextstyle(&f);
        setbkmode(TRANSPARENT);
        return true;
    }
    
    int init(int width, int height, int showconsole = 0, LPCTSTR fontname = nullptr, int fontheight = 18)
    {
        int ok = 0;
        if ((exim::DisplayInfo.win = exim::init_display(width, height, showconsole)) != NULL) {
            ok++;
        }
        if (exim::init_text(fontname, fontheight)) {
            ok++;
        }
        return ok;
    }
    
    typedef struct {
        color_t r;
        color_t g;
        color_t b;
    } Color;
    
    typedef struct {
        color_t r;
        color_t g;
        color_t b;
        color_t a;
    } ColorEx;
    
    enum __place {
        BOTTOMLEFT, BOTTOM, BOTTOMRIGHT, LEFT, CENTER, RIGHT, TOPLEFT, TOP, TOPRIGHT
    };
    
    enum __direct {
        X = 0b01, Y = 0b10
    };
    class __draw;
    class image {
        private:
            int w;
            int h;
            exim::ColorEx *cp; // color pointer
        public:
            int getw();
            int geth();
            exim::ColorEx &at(int w, int h);
        public:
            exim::image();
            exim::image(int w, int h);
            exim::image(const exim::image &from);
            ~image(); // 240801
            GETEXIMAPI void get(const exim::image *from);
            void load(LPCTSTR filename, int w = 0, int h = 0, bool _resize = false);
            void load(IMAGE *p);
            void resize(int width, int height);
            exim::image scale(int new_width, int new_height);
            void scale(exim::image &self, int nw, int nh);
            exim::image &flip(int8_t direct);
            //exim::image rotate(double degree);
            void inverse();
            void operator=(exim::image &from);
            //void operator=(exim::image &&from);
            unsigned long set_colorkey(exim::Color &c);
            void set_alpha(color_t alp);
            IMAGE to_image();
            void to_image(IMAGE *p);
            //void Parallelogram(int x, int y); // 右下角的点平移后坐标
        private:
            friend class exim::__draw;
    };
    
    
    class __draw {
        public:
        void line(exim::image &self, int x0, int y0, int x1, int y1, const exim::Color &c, int lw = 1);
        void fill(exim::image &self, const exim::Color &c);
        void fill(exim::image &self, const exim::ColorEx &c);
        void fill(const exim::Color &c);
        void rect(exim::image &self, int x, int y, int w, int h, const exim::Color &c, int lw = 0);
        //void line(exim::image &self, int x0, int y0, int x1, int y1, exim::ColorEx &c);
        void point(exim::image &self, int x, int y, int len, color_t r, color_t g, color_t b);
        void text(TCHAR *str, int x, int y, COLORREF col, int place = exim::CENTER);
        void multitext(LPCTSTR str, int x, int y, COLORREF col, int gap = 2, TCHAR sep = '\n');
        void multitext(LPCTSTR str, int x, int y, int w, int h, COLORREF col, int gap = 2, TCHAR sep = '\0');
        void blit(exim::image &self, int x, int y);
        void blit(exim::image &self, int x, int y, int place);
        void blit(exim::image &self, int x, int y, int place, int8_t alpha);
        void blit(exim::image &self, exim::image &to, int x, int y);
        exim::image flip(exim::image &self, int8_t direct);
        //void blit(exim::image &self, exim::image &to, int x, int y, int place, int8_t alpha);
        //void show(exim::image &self, int center_x, int center_y);
    } draw;
    /*
    class {
        public:
        void blit(exim::image &self, int x, int y);
        void show(exim::image &self, int center_x, int center_y);
    } fastdraw;*/
    
    class __color {
        public:
        template<typename C1, typename C2, typename = \
        typename std::enable_if<(std::is_same<exim::Color, C1>::value || std::is_same<exim::ColorEx, C1>::value)\
        && (std::is_same<exim::Color, C2>::value || std::is_same<exim::ColorEx, C2>::value)>::type\
        >
        int8_t eq(C1 &color1, C2 &color2) {
            if ((color1.r == color2.r) and (color1.g is color2.g) and (color1.b is color2.b)) {
                return 1;
            } else return 0;
        }
        template <typename C1, class C2> void assign(C1 &color1, C2 &color2) {
            static_assert(
                (std::is_same<exim::Color,C1>::value || std::is_same<exim::ColorEx,C1>::value) &&
                (std::is_same<exim::Color,C2>::value || std::is_same<exim::ColorEx,C2>::value),
                "exim.color.assign need Color/ColorEx."
            );
            color1.r = color2.r;
            color1.g = color2.g;
            color1.b = color2.b;
        }
        template < typename C1, typename C2, typename = \
            typename std::enable_if<(std::is_same<exim::Color, C1>::value ||\
            std::is_same<exim::ColorEx, C1>::value)>::type\
        >
        void set(C1 &self, color_t r, color_t g, color_t b) {
            self.r = r;
            self.g = g;
            self.b = b;
        }
        template < typename C1, typename C2, typename = \
            typename std::enable_if<(std::is_same<exim::Color, C1>::value ||\
            std::is_same<exim::ColorEx, C1>::value)>::type\
        >
        COLORREF rgb(C1 &self) {
            return RGB(self.r, self.g, self.b);
        }
        public:
        const exim::Color White = {255, 255, 255};
        const exim::Color Black = {0, 0, 0};
        const exim::Color Red = {255, 0, 0};
        const exim::Color Green = {0, 255, 0};
        const exim::Color Blue = {0, 0, 255};
        const exim::Color Yellow = {255, 255, 0};
        
        const exim::ColorEx Transparent = {0, 0, 0, 0};
    }color;
    
    template <typename T> T mid(T value, T _min, T _max) {
        if (value < _min) {
            return _min;
        } elif (value > _max) {
            return _max;
        } else {
            return value;
        }
    }
    
    bool is_same_color(exim::ColorEx &c1, exim::Color &c2) {
        if((c1.r == c2.r) && (c1.g == c2.g) && (c1.b == c2.b)) {
            return true;
        } else {
            return false;
        }
    }
    
} // namespace exim


// impl
int exim::image::getw() {
    return this->w;
}
int exim::image::geth() {
    return this->h;
}
exim::image::image() {
    this->w = 0;
    this->h = 0;
    this->cp = nullptr;
}
exim::image::image(int w, int h) {
    this->w = w;
    this->h = h;
    this->cp = new exim::ColorEx[w * h + 1];
}
exim::image::image(const exim::image &from) {
    *this = const_cast<exim::image&>(from);
}
void exim::image::resize(int w, int h) {
    if(this->w is w  and  this->h is h) {
        return;
    }
    this->w = w;
    this->h = h;
    if (this->cp == nullptr) {
        pass;
    } else {
        delete[] this->cp;
    }
    this->cp = new exim::ColorEx[w * h + 1];
}
void exim::image::operator=(exim::image &from) {
    if (this->cp == nullptr) {
        this->cp = new exim::ColorEx[from.getw() * from.geth() + 1];
    } else {
        if ((this->w * this->h + 1)  is  (from.getw() * from.geth() + 1)) {
            pass;
        } else {
            delete[] this->cp;
            this->cp = new exim::ColorEx[from.getw() * from.geth() + 1];
        }
    }
    this->w = from.getw();
    this->h = from.geth();
    exim::draw.blit(from, *this, 0, 0);
}/*
void exim::image::operator=(exim::image &&from) {
    this->w = from.w;
    this->h = from.h;
    if (this->cp != nullptr) {
        delete[] this->cp;
    }
    this->cp = from.cp;
}*/

exim::ColorEx &exim::image::at(int wx, int hy) {
    if (0 <= wx and wx < this->w  and  0 <= hy and hy < this->h) {
        return this->cp[hy * this->w + wx];
    } else {
        static TCHAR s[260];
        _stprintf(s, _T("exim.image.at: outofrange. (w=%d/%d, h=%d/%d)"), wx, this->w, hy, this->h);
        throw exim::Exception(s);
    }
}
void exim::image::load(LPCTSTR filename, int w, int h, bool _resize)
{
    IMAGE im;
    loadimage(&im, filename, w, h, _resize);
    this->load(&im);
}
void exim::image::load(IMAGE *p) {
    this->resize(p->getwidth(), p->getheight());
    DWORD *p_ptr = GetImageBuffer(p);
    for(int x = 0; x < p->getwidth(); x++) {
        for(int y = 0; y < p->getheight(); y++) {
            this->at(x, y).r = GetRValue(p_ptr[y * p->getwidth() + x]);
            this->at(x, y).g = GetGValue(p_ptr[y * p->getwidth() + x]);
            this->at(x, y).b = GetBValue(p_ptr[y * p->getwidth() + x]);
            this->at(x, y).a = 255;
        }
    }
}
unsigned long exim::image::set_colorkey(exim::Color &c) {
    unsigned long i = 0;
    for(int x = 0; x < this->w; x++) {
        for(int y = 0; y < this->h; y++) {
            if (exim::is_same_color(this->at(x, y), c)) {
                this->at(x,y).a = 0;
                i++;
            }
        }
    }
    return i;
}
GETEXIMAPI void exim::image::get(const exim::image *from) {
    this->w = from->w;
    this->h = from->h;
    this->cp = from->cp;
}

void exim::__draw::text(TCHAR *str, int x, int y, COLORREF col, int place) {
    settextcolor(col);
    const int nw = textwidth(str);
    const int nh = textheight(str);
    switch (place)
    {
    case exim::BOTTOMLEFT:{
        outtextxy(x, y-nh, str);
    }
        break;
    
    case exim::BOTTOM:{
        outtextxy(x - nw/2, y - nh, str);
    } break;
    
    case exim::BOTTOMRIGHT:{
        outtextxy(x - nw, y - nh, str);
    } break;
    
    case exim::LEFT:{
        outtextxy(x, y - nh/2, str);
    } break;
    
    case exim::CENTER:{
        outtextxy(x - nw/2, y - nh/2, str);
    } break;
    
    case exim::RIGHT:{
        outtextxy(x - nw, y - nh/2, str);
    } break;
    
    case exim::TOPLEFT:{
        outtextxy(x, y, str);
    } break;
    
    case exim::TOP:{
        outtextxy(x - nw/2, y, str);
    } break;
    
    case exim::TOPRIGHT :{
        outtextxy(x - nw, y, str);
    } break;
    
    default:
        static TCHAR err[500];
        _stprintf(err, _T("exim.draw.text: invalid text place %d. (text=%s)"), place, str);
        throw exim::Exception(err);
    }
}
void exim::__draw::multitext(LPCTSTR str, int x, int y, COLORREF col, int gap, TCHAR sep)
{
    //throw std::exception("todo");
    exim::draw.multitext(str, x, y, 9999, 9999, col, gap, sep);
}
void exim::__draw::multitext
(LPCTSTR str, int x, int y, int w, int h, COLORREF col, int gap, TCHAR sep)
{
    int xn = x;
    int yn = y;
    const int xmax = x + w;
    const int ymax = y + h;
    const int yadd = textheight(str) + gap;
    settextcolor(col);
    const TCHAR *p = &str[0];
    while(true) {
        if (*p is _T('\0')) {
            return;
        }
        if (yn > ymax) {
            return;
        }
        if (*p is sep) {
            xn = x;
            yn += yadd;
            p++;
            continue;
        }
        outtextxy(xn, yn, *p);
        const int xadd = textwidth(*p);
        xn += xadd;
        if (xn > xmax) {
            xn = x;
            yn += yadd;
        }
        p++;
    }
}
void exim::__draw::blit(exim::image &self, int x, int y) {
    int xn = x;
    int yn = y;
    // limit
    if (xn < 0) {
        xn = 0;
    } elif (xn >= exim::DisplayInfo.width) {
        return;
    }
    if (yn < 0) {
        yn = 0;
    } elif (yn >= exim::DisplayInfo.height) {
        return;
    }
    int xr = x + self.w;
    int yr = y + self.h;
    if (xr < 0) {
        return;
    } elif (xr >= exim::DisplayInfo.width) {
        xr = exim::DisplayInfo.width;
    }
    if (yr < 0) {
        return;
    } elif (yr >= exim::DisplayInfo.height) {
        yr = exim::DisplayInfo.height;
    }
    int xs = xn - x;
    DWORD *ptr = GetImageBuffer();
    for(int _xn = xn; _xn < xr; _xn++) {
        int ys = yn - y;
        for (int _yn = yn; _yn < yr; _yn++) {
            exim::ColorEx *cptr = &self.at(xs, ys);
            if (cptr->a is 255) {
                COLORREF col = RGB(cptr->r, cptr->g, cptr->b);
                ptr[_yn * getwidth() + _xn] = col;
            } elif (cptr->a is 0) {
                pass;
            } else {
                float per = float(cptr->a) / 255;
                color_t r = cptr->r * (1.0 - per) + GetRValue(ptr[_yn * getwidth() + _xn]) * per;
                color_t g = cptr->g * (1.0 - per) + GetGValue(ptr[_yn * getwidth() + _xn]) * per;
                color_t b = cptr->b * (1.0 - per) + GetBValue(ptr[_yn * getwidth() + _xn]) * per;
                ptr[_yn * getwidth() + _xn] = RGB(r, g, b);
            }
            ys++;
        }
        xs++;
    }
}
void exim::__draw::blit(exim::image &self, int x, int y, int place, int8_t alpha) {
    //throw std::exception("todo");
    int w = self.w;
    int h = self.h;
    int xn = x, yn = y;
    switch (place)
    {
    case exim::BOTTOMLEFT:{
        yn -= h;
    }break;
    
    case exim::BOTTOM:{
        yn -= h;
        xn -= (w/2);
    } break;
    
    case exim::BOTTOMRIGHT:{
        yn -= h;
        xn -= w;
    } break;
    
    case exim::LEFT:{
        yn -= (h/2);
    }break;
    
    case exim::CENTER:{
        yn -= (h/2);
        xn -= (w/2);
    } break;
    
    case exim::RIGHT:{
        yn -= (h/2);
        xn -= w;
    }break;
    
    case exim::TOPLEFT:{
        pass;
    }break;
    
    case exim::TOP:{
        xn -= (w/2);
    }break;
    
    case exim::TOPRIGHT:{
        xn -= w;
    } break;
    
    default:
        static TCHAR err[500];
        _stprintf(err, _T("exim.draw.blit: invalid text place %d. (x=%d,y=%d)"), place, x,y);
        throw exim::Exception(err);
        return;
    }
    //exim::draw.blit(self, xn, yn);
    
    const int _x = xn;
    const int _y = yn;
    
    // limit
    if (xn < 0) {
        xn = 0;
    } elif (xn >= exim::DisplayInfo.width) {
        return;
    }
    if (yn < 0) {
        yn = 0;
    } elif (yn >= exim::DisplayInfo.height) {
        return;
    }
    int xr = _x + self.w;
    int yr = _y + self.h;
    if (xr < 0) {
        return;
    } elif (xr >= exim::DisplayInfo.width) {
        xr = exim::DisplayInfo.width;
    }
    if (yr < 0) {
        return;
    } elif (yr >= exim::DisplayInfo.height) {
        yr = exim::DisplayInfo.height;
    }
    int xs = xn - _x;
    DWORD *ptr = GetImageBuffer();
    for(int _xn = xn; _xn < xr; _xn++) {
        int ys = yn - _y;
        for (int _yn = yn; _yn < yr; _yn++) {
            exim::ColorEx *cptr = &self.at(xs, ys);
            if (cptr->a is 255) {
                //COLORREF col = RGB(cptr->r, cptr->g, cptr->b);
                //ptr[_yn * getwidth() + _xn] = col;
                float per = float(alpha) / 255;
                color_t r = cptr->r * (1.0 - per) + GetRValue(ptr[_yn * getwidth() + _xn]) * per;
                color_t g = cptr->g * (1.0 - per) + GetGValue(ptr[_yn * getwidth() + _xn]) * per;
                color_t b = cptr->b * (1.0 - per) + GetBValue(ptr[_yn * getwidth() + _xn]) * per;
                ptr[_yn * getwidth() + _xn] = RGB(r, g, b);
            } elif (cptr->a is 0) {
                pass;
            } else {
                float per = float(exim::mid(int(cptr->a)+ (int)alpha, 0, 255)) / 255;
                color_t r = cptr->r * (1.0 - per) + GetRValue(ptr[_yn * getwidth() + _xn]) * per;
                color_t g = cptr->g * (1.0 - per) + GetGValue(ptr[_yn * getwidth() + _xn]) * per;
                color_t b = cptr->b * (1.0 - per) + GetBValue(ptr[_yn * getwidth() + _xn]) * per;
                ptr[_yn * getwidth() + _xn] = RGB(r, g, b);
            }
            ys++;
        }
        xs++;
    }
    
}
void exim::__draw::blit(exim::image &self, int x, int y, int place) {
    int w = self.w;
    int h = self.h;
    int xn = x, yn = y;
    switch (place)
    {
    case exim::BOTTOMLEFT:{
        yn -= h;
    }break;
    
    case exim::BOTTOM:{
        yn -= h;
        xn -= (w/2);
    } break;
    
    case exim::BOTTOMRIGHT:{
        yn -= h;
        xn -= w;
    } break;
    
    case exim::LEFT:{
        yn -= (h/2);
    }break;
    
    case exim::CENTER:{
        yn -= (h/2);
        xn -= (w/2);
    } break;
    
    case exim::RIGHT:{
        yn -= (h/2);
        xn -= w;
    }break;
    
    case exim::TOPLEFT:{
        pass;
    }break;
    
    case exim::TOP:{
        xn -= (w/2);
    }break;
    
    case exim::TOPRIGHT:{
        xn -= w;
    } break;
    
    default:
        static TCHAR err[500];
        _stprintf(err, _T("exim.draw.blit: invalid text place %d. (x=%d,y=%d)"), place, x,y);
        throw exim::Exception(err);
        return;
    }
    exim::draw.blit(self, xn, yn);
}

void exim::__draw::blit(exim::image &self, exim::image &to, int x, int y) {
    if (x >= to.w or y >= to.h) {
        return;
    }
    //int xl, yl;//len
    if(x + self.w < 0 or y + self.h < 0) {
        return;
    }
    for(int xw = 0; xw < self.w; xw++) {
        int xt = xw + x;
        for(int hy = 0; hy < self.h; hy++) {
            int yt = hy + y;
            if(0 <= xt and xt < to.w  and  0 <= yt and yt < to.h) {
                exim::ColorEx *cptr = &self.at(xw, hy);
                exim::ColorEx *cp2  = &to.at(xt, yt);
                if (cptr->a is 255) {
                    COLORREF col = RGB(cptr->r, cptr->g, cptr->b);
                    cp2->r = cptr->r;
                    cp2->g = cptr->g;
                    cp2->b = cptr->b;
                    cp2->a = 255;
                } elif (cptr->a is 0) {
                    pass;
                } else {
                    float per = float(cptr->a) / 255;
                    cp2->r = cptr->r * (1.0 - per) + cp2->r * per;
                    cp2->g = cptr->g * (1.0 - per) + cp2->g * per;
                    cp2->b = cptr->b * (1.0 - per) + cp2->b * per;
                }
            }
        }
    }
}
exim::image/*&&*/ exim::image::scale(int nw, int nh) {
    throw exim::Exception(_T("exim.image.scale(int,int): NotImplementError. "));
    exim::image im(nw, nh);
    const double perx = nw / this->w;
    const double pery = nh / this->h;
    for(int nx = 0; nx < nw; nx++) {
        for(int ny = 0; ny < nh; ny++) {
            // old_place
            int ox = exim::mid<int>(int(nx / perx), 0, this->w-1);
            int oy = exim::mid<int>(ny / pery, 0, this->h-1);
            exim::ColorEx *po = &this->at(ox, oy);
            exim::ColorEx *pn = &im.at(nx, ny);
            pn->r = po->r;
            pn->g = po->g;
            pn->b = po->b;
            pn->a = po->a;
        }
    }
    return /*std::move*/(im);
}
void exim::image::scale(exim::image &to, int nw, int nh) {
    to.resize(nw, nh);
    const double perx = double(nw) / this->w;
    const double pery = double(nh) / this->h;
    for(int nx = 0; nx < nw; nx++) {
        for(int ny = 0; ny < nh; ny++) {
            // old_place
            int ox = exim::mid<int>(int(nx / perx), 0, this->w-1);
            int oy = exim::mid<int>(ny / pery, 0, this->h-1);
            exim::ColorEx *po = &this->at(ox, oy);
            exim::ColorEx *pn = &to.at(nx, ny);
            pn->r = po->r;
            pn->g = po->g;
            pn->b = po->b;
            pn->a = po->a;
        }
    }
}
void exim::image::inverse() {
    for(int x = 0; x < this->w; x++) {
        for(int y = 0; y < this->h; y++) {
            exim::ColorEx *p = &this->at(x, y);
            p->r = 255 - p->r;
            p->g = 255 - p->g;
            p->b = 255 - p->b;
        }
    }
}
void exim::image::set_alpha(color_t alp) {
    for(int x = 0; x < this->w; x++) {
        for(int y = 0; y < this->h; y++) {
            this->at(x, y).a = alp;
        }
    }
}
IMAGE exim::image::to_image() {
    IMAGE p(this->w, this->h);
    DWORD *ptr = GetImageBuffer(&p);
    for(int y = 0; y < this->h; y++) {
        for(int x = 0; x < this->w; x++) {
            exim::ColorEx *pc = &this->at(x, y);
            *ptr = RGB(pc->r, pc->g, pc->b);
            ptr++;
        }
    }
    return p;
}
void exim::image::to_image(IMAGE *p) {
    p->Resize(this->w, this->h);
    DWORD *ptr = GetImageBuffer(p);
    for(int y = 0; y < this->h; y++) {
        for(int x = 0; x < this->w; x++) {
            exim::ColorEx *pc = &this->at(x, y);
            *ptr = RGB(pc->r, pc->g, pc->b);
            ptr++;
        }
    }
}
void exim::__draw::point(exim::image &self, int x, int y, int len, color_t r, color_t g, color_t b)
{
    const int dx = len / 2;
    const int xl = x - dx;
    const int xr = x + dx;
    const int yl = y - dx;
    const int yr = y + dx;
    for(int w = xl; w <= xr; w++) {
        for (int h = yl; h <= yr; h++) {
            if(0 <= w and w < self.w  and 0 <= h and h < self.h) {
                exim::ColorEx *p = &self.at(w, h);
                p->r = r;
                p->g = g;
                p->b = b;
            }
        }
    }
}
void exim::__draw::line(exim::image &self, int x0, int y0, int x1, int y1, const exim::Color &c, int lw)
{
    if (lw < 1) {
        lw = 1;
    }
    if (x0 is x1) {
        int yl = min(y0, y1);
        int yr = max(y0, y1);
        for(int y = yl; y <= yr; y++) {
            exim::draw.point(self, x0, y, lw, c.r, c.g, c.b);
        }
    } else {
        int xl, xr, yl, yr;
        if (x0 > x1) {
            xl = x1;
            xr = x0;
            yl = y1;
            yr = y0;
        } else {
            xl = x0;
            yl = y0;
            xr = x1;
            yr = y1;
        }
        const double k = double(yr - yl) / (xr - xl);
        const int b = yr - k * xr;
        for(int x = xl; x <= xr; x++) {
            int y = k * x + b;
            exim::draw.point(self, x, y, lw, c.r, c.g, c.b);
        }
    }
}
void exim::__draw::fill(exim::image &self, const exim::Color &c)
{
    if (self.cp is nullptr) {
        return;
    }
    for(int x = 0; x < self.w; x++) {
        for(int y = 0; y < self.h; y++) {
            exim::ColorEx *p = &self.at(x, y);
            p->r = c.r;
            p->g = c.g;
            p->b = c.b;
        }
    }
}
void exim::__draw::fill(exim::image &self, const exim::ColorEx &c)
{
    if (self.cp is nullptr) {
        return;
    }
    for(int x = 0; x < self.w; x++) {
        for(int y = 0; y < self.h; y++) {
            exim::ColorEx *p = &self.at(x, y);
            p->r = c.r;
            p->g = c.g;
            p->b = c.b;
            p->a = c.a;
        }
    }
}
void exim::__draw::fill(const exim::Color &c) {
    DWORD *const p = GetImageBuffer();
    const int w = getwidth();
    for(int x = 0; x < getwidth(); x++) {
        for(int y = 0; y < getheight(); y++) {
            p[y * w + x] = RGB(c.r, c.g, c.b);
        }
    }
}
void exim::__draw::rect(exim::image &self, int x, int y, int w, int h, const exim::Color &c, int lw)
{
    if(self.cp is nullptr) {
        throw exim::Exception(_T("exim.draw.rect: NullPointerException."));
    }
    if (lw <= 0) {
        lw = 9990;
    }
    const int xl = max(0, x);
    const int xr = min(x+w,  self.w-1);
    if (xl > xr) {
        return;
    }
    const int yl = max(0, y);
    const int yr = min(y+h, self.h-1);
    if (yl > yr) {
        return;
    }
    int lx = xr - xl;
    int ly = yr - yl;
    while (lx >= 0 and ly >= 0) {
        for(int i = 0; i < lx; i++) {
            exim::draw.point(self, x, y, 1, c.r, c.g, c.b);
            x++;
        }
        for(int i = 0; i < ly; i++) {
            exim::draw.point(self, x, y, 1, c.r, c.g, c.b);
            y++;
        }
        for(int i = 0; i < lx; i++) {
            exim::draw.point(self, x, y, 1, c.r, c.g, c.b);
            x--;
        }
        for(int i = 0; i < ly; i++) {
            exim::draw.point(self, x, y, 1, c.r, c.g, c.b);
            y--;
        }
        lw --;
        if (lw <= 0) {
            break;
        }
        else {
            x++; y++;
            lx -= 2;
            ly -= 2;
        }
    }
}
exim::image exim::__draw::flip(exim::image &self, int8_t direct) {
    exim::image im(self.w, self.h);
    switch (direct)
    {
    case exim::X: {
        for(int y = self.h-1; y >= 0; y--) {
            int dx = 0;
            for(int x = self.w-1; x >= 0; x--) {
                exim::ColorEx *s = &self.at(x, y);
                exim::ColorEx *i = &im.at(dx, y);
                i->r = s->r;
                i->g = s->g;
                i->b = s->b;
                i->a = s->a;
                dx++;
            }
        }
    }
        break;
    
    case exim::Y: {
        for(int x = self.w-1; x >= 0; x--) {
            int dy = 0;
            for(int y = self.h-1; y >= 0; y--) {
                exim::ColorEx *s = &self.at(x, y);
                exim::ColorEx *i = &im.at(x, dy);
                i->r = s->r;
                i->g = s->g;
                i->b = s->b;
                i->a = s->a;
                dy++;
            }
        }
    } break;
    
    case exim::X | exim::Y: {
        for(int x = 0; x < self.w; x++) {
            for(int y = 0; y < self.h; y++) {
                exim::ColorEx *s = &self.at(x, y);
                exim::ColorEx *i = &im.at(im.w - x -1, im.h - y -1);
                i->r = s->r;
                i->g = s->g;
                i->b = s->b;
                i->a = s->a;
            }
        }
    } break;
    
    default:
        static TCHAR err[100];
        _stprintf(err, _T("exim.draw.flip: invalid flip direct %d."), int(direct));
        throw exim::Exception(err);
    }
    return std::move(im);
}
exim::image& exim::image::flip(int8_t direct) {
    switch (direct)
    {/*
    case exim::X: {
        for(int y = this->h-1; y >= 0; y--) {
            int dx = 0;
            for(int x = this->w-1; x >= 0; x--) {
                exim::ColorEx *s = &this->at(x, y);
                exim::ColorEx *i = &this->at(dx, y);
                exim::ColorEx t{i->r, i->g, i->b, i->a};
                i->r = s->r;
                i->g = s->g;
                i->b = s->b;
                i->a = s->a;
                s->r = t.r;
                s->g = t.g;
                s->b = t.b;
                s->a = t.a;
                dx++;
            }
        }
    }
        break;
    
    case exim::Y: {
        for(int x = this->w - 1; x >= 0; x--) {
            int dy = 0;
            for(int y = this->h - 1; y >= 0; y--) {
                exim::ColorEx *s = &this->at(x, y);
                exim::ColorEx *i = &this->at(x, dy);
                exim::ColorEx t{i->r, i->g, i->b, i->a};
                i->r = s->r;
                i->g = s->g;
                i->b = s->b;
                i->a = s->a;
                s->r = t.r;
                s->g = t.g;
                s->b = t.b;
                s->a = t.a;
                dy++;
            }
        }
    } break;*/
    
    case exim::X: {
        exim::ColorEx t;
        for(int x = 0; x < this->w / 2; x++) {
            for(int y = 0; y < this->h; y++) {
                exim::ColorEx *s = &this->at(x, y);
                exim::ColorEx *i = &this->at(this->w - x -1, y);
                //exim::ColorEx t{i->r, i->g, i->b, i->a};
                t.r = i->r;
                t.g = i->g;
                t.b = i->b;
                t.a = i->a;
                i->r = s->r;
                i->g = s->g;
                i->b = s->b;
                i->a = s->a;
                s->r = t.r;
                s->g = t.g;
                s->b = t.b;
                s->a = t.a;
            }
        }
    } break;
    
    case exim::Y: {
        exim::ColorEx t;
        for(int x = 0; x < this->w; x++) {
            for(int y = 0; y < this->h / 2; y++) {
                exim::ColorEx *s = &this->at(x, y);
                exim::ColorEx *i = &this->at(x, this->h - y - 1);
                t.r = i->r;
                t.g = i->g;
                t.b = i->b;
                t.a = i->a;
                i->r = s->r;
                i->g = s->g;
                i->b = s->b;
                i->a = s->a;
                s->r = t.r;
                s->g = t.g;
                s->b = t.b;
                s->a = t.a;
            }
        }
    } break;
    
    case exim::X | exim::Y: {
        // /*
        throw exim::Exception(_T("exim.image.flip: NotImplement. "));
        for(int x = 0; x < this->w / 2; x++) {
            for(int y = 0; y < this->h / 2; y++) {
                exim::ColorEx *s = &this->at(x, y);
                exim::ColorEx *i = &this->at(this->w - x -1, this->h - y -1);
                exim::ColorEx t{i->r, i->g, i->b, i->a};
                i->r = s->r;
                i->g = s->g;
                i->b = s->b;
                i->a = s->a;
                s->r = t.r;
                s->g = t.g;
                s->b = t.b;
                s->a = t.a;
            }
        }
        // */
    } break;
    
    default:
        static TCHAR err[100];
        _stprintf(err, _T("exim.image.flip: invalid flip direct %d."), int(direct));
        throw exim::Exception(err);
    }
    return *this;
}

namespace exim
{
    image::~image() {
        if(this->cp != nullptr) {
            delete[] this->cp;
        }
    }
} // namespace exim


//240728
#undef is